home *** CD-ROM | disk | FTP | other *** search
/ Carousel Volume 2 #1 / carousel.iso / mactosh / util / sortmenu.sit / SortMenu Code next >
Text File  |  1985-08-16  |  6KB  |  247 lines

  1. ; File SortMenu.TXT
  2. ;--------------------------------------------------------------------
  3. ;
  4. ;  This program installs code in the system heap that patches out
  5. ;  AddResMenu so it returns with the added names sorted in alphabetical
  6. ;  order.  It works internationally, since it uses Pack6 for the
  7. ;  string compare.
  8. ;
  9. ;     written by Andy Hertzfeld  04-Aug-85  (in the big Apple)
  10. ;
  11. ;--------------------------------------------------------------------
  12.  
  13. INCLUDE MacTraps.D
  14.  
  15. XDEF        START
  16.  
  17. START
  18.         BRA    InstallIt
  19.  
  20. AddResPatch
  21.         LEA    theMenuHandle,A0    ;get locals address
  22.         MOVE.L    8(SP),A1        ;get menu handle
  23.         MOVE.L    A1,(A0)+        ;remember menu handle
  24.         MOVE.L    (SP)+,(A0)        ;remember return address
  25.  
  26.         SUBQ    #2,SP
  27.         MOVE.L    A1,-(SP)        ;push the menu handle
  28.         _CountMItems            ;count the items
  29.         LEA    baseItem,A0
  30.         MOVE.W    (SP)+,(A0)        ;remember # of items
  31.  
  32. ; now run the old routine
  33.  
  34.         MOVE.L    OldARMenu,A0        ;get old routine
  35.         JSR    (A0)            ;invoke it
  36.         
  37. ; allocate work space and save registers
  38.         
  39.         LINK    A6,#-260        ;space for string plus 4
  40.         MOVEM.L    D3-D6/A2-A4,-(SP)    ;save some work registers
  41.         
  42. ; load Pack6 into memory
  43.  
  44.         SUBQ    #4,SP
  45.         MOVE.L    #$5041434B,-(SP)    ;push PACK
  46.         MOVE    #6,-(SP)        ;pack 6
  47.         _GetResource            ;load it in
  48.         ADDQ    #4,SP
  49.  
  50. ; now count the # of items now in the menu and compute how many were added
  51.  
  52.         SUBQ    #2,SP            ;reserve space for result
  53.         MOVE.L    theMenuHandle,A2    ;keep menuHandle in A2
  54.         MOVE.L    A2,-(SP)        ;push it
  55.         _CountMItems            ;count em up
  56.         MOVE.W    (SP)+,D3        ;keep # of items in D3
  57.         MOVE.W    BaseItem,D4        ;keep base items in D4
  58.  
  59.         MOVE    D3,D5            ;copy item count
  60.         SUB    D4,D5            ;compute # of new items        
  61.         BEQ    DoneARMenu        ;if none, we're done
  62.         
  63. ; OK, now we're ready to do the real work.  A3 will point to the current
  64. ; item we're bubbling.  First, skip to it.
  65.  
  66.         MOVE.L    (A2),A3            ;start at the beginning
  67.         ADD.W    #14,A3            ;skip header
  68.         MOVEQ    #0,D0            ;clear out high part
  69.         MOVE.B    (A3)+,D0        ;get title length
  70.         ADD.W    D0,A3            ;skip over it
  71.         
  72. ; skip the number of items in D4
  73.         
  74.         BRA.S    NextSkipBase
  75. SkipBaseLoop
  76.         MOVE.B    (A3),D0            ;get item length
  77.         ADD.W    D0,A3            ;skip item
  78.         ADDQ.W    #5,A3            ;skip length, prop bytes
  79. NextSkipBase        
  80.         DBRA    D4,SkipBaseLoop
  81.         
  82. ; remember the first item we're starting with
  83.  
  84.         MOVE.L    A3,A4
  85.         
  86. ; here's the sort loop.  Compare the current item with the next one and,
  87. ; if it's lexically greater, swap them
  88.  
  89. SortLoop0
  90.         MOVE.L    A4,A3            ;start with first one
  91. SortLoop1        
  92.         MOVEQ    #0,D0
  93.         MOVE.B    (A3),D0
  94.         LEA    5(A3,D0),A0        ;compute next one
  95.         MOVE.L    A0,D6            ;remember for later
  96.         
  97.         TST.B    (A0)            ;is it the last?
  98.         BEQ.S    NextIteration        ;if so, skip
  99.  
  100. ; use Pack6 for the string compare
  101.  
  102.         MOVE.L    A3,A1
  103.         SUBQ    #2,SP            ;reserve space for result
  104.         MOVEQ    #0,D1
  105.         MOVEQ    #0,D2
  106.         MOVE.B    (A1)+,D1        ;get 1st length
  107.  
  108. ; if it begins with null, skip it
  109.  
  110.         TST.B    (A1)
  111.         BNE.S    @0
  112.         ADDQ    #1,A1
  113.         SUBQ    #1,D1
  114. @0
  115.         MOVE.L    A1,-(SP)        ;push string
  116.         MOVE.B    (A0)+,D2        ;get 2nd length
  117.  
  118. ; ditto for second string
  119.  
  120.         TST.B    (A0)
  121.         BNE.S    @1
  122.         ADDQ    #1,A0
  123.         SUBQ    #1,D2
  124. @1
  125.         MOVE.L    A0,-(SP)        ;push string
  126.         MOVE.W    D1,-(SP)        ;push 1st length
  127.         MOVE.W    D2,-(SP)        ;push 2nd string
  128.  
  129.         MOVE.W    #10,-(SP)        ;push selector
  130.         _Pack6                ;invoke string compare
  131.         MOVE.W    (SP)+,D0        ;get result
  132.         BLE.S    NextItem        ;if in order, skip
  133.  
  134. ; the first item is greater than the second, so swap them.  First move
  135. ; first item into a temporary location
  136.  
  137.         MOVE.L    A3,A0            ;source address
  138.         BSR.S    GetSourceLen
  139.         LEA    -256(A6),A1        ;destination
  140.         _BlockMove
  141.  
  142. ; move the second item over the first
  143.  
  144.         MOVE.L    D6,A0            ;source address
  145.         MOVE.L    A3,A1            ;destination address
  146.         BSR.S    GetSourceLen
  147.         _BlockMove
  148.  
  149. ; move the first back in
  150.         
  151.         LEA    -256(A6),A0        ;source address
  152.         MOVEQ    #0,D0
  153.         MOVE.B    (A3),D0
  154.         LEA    5(A3,D0),A1        ;destination address
  155.         MOVE.L    A1,D6            ;new next item
  156.         BSR.S    GetSourceLen
  157.         _BlockMove
  158.  
  159. ; now try the next item, bubbling down until we've reached the bottom
  160.  
  161. NextItem
  162.         MOVE.L    D6,A3            ;point A3 to next item
  163.         BRA.S    SortLoop1        ;go put it in order
  164.         
  165. ; GetSourceLen is a utility that returns the length of the string pointed
  166. ; to by A0 plus 5 in D0.
  167.  
  168. GetSourceLen
  169.         MOVEQ    #0,D0            ;clear D0
  170.         MOVE.B    (A0),D0            ;get the length
  171.         ADDQ    #5,D0            ;include length, prop bytes
  172.         RTS
  173.         
  174. ; NextIteration is the bottom of the outer loop.  Repeat it enough times
  175. ; until it's sorted
  176.  
  177. NextIteration
  178.         SUBQ    #1,D5            ;more to do?
  179.         BGT.S    SortLoop0        ;if so, go do it
  180.         
  181. ; we're all done so deallocate storage, restore registers and return
  182.  
  183. DoneARMenu
  184.         MOVEM.L    (SP)+,D3-D6/A2-A4    ;restore work registers
  185.         UNLK    A6            ;release stack frame
  186.         
  187.         MOVE.L    theReturnAddress,A0    ;recover return address
  188.         JMP    (A0)            ;bye-bye!
  189.         
  190. ; our local variables
  191.  
  192. theMenuHandle
  193.         DC.W    0,0
  194. theReturnAddress
  195.         DC.W    0,0
  196. BaseItem
  197.         DC.W    0
  198. OldARMenu
  199.         DC.W    0,0
  200.         
  201. ; InstallIt is the routine that installs the above in the system heap
  202.  
  203. InstallIt
  204.  
  205. ; get the address of the current AddResMenu routine and remember it
  206.  
  207.         MOVE.W    #$14D,D0        ;trap ID of AddResMenu
  208.         _GetTrapAddress            ;get old address
  209.         
  210.         LEA    OldARMenu,A1
  211.         MOVE.L    A0,(A1)            ;remember old address
  212.  
  213. ; compute size of code and allocate in system heap, then move it in
  214.  
  215.         LEA    AddResPatch,A2
  216.         LEA    InstallIt,A0
  217.         MOVE.L    A0,D0
  218.         SUB.L    A2,D0            ;compute size
  219.         MOVE.L    D0,D1            ;remember size
  220.         
  221.         DC.W    $A51E            ;allocate in system heap
  222.         BNE    NoInstall        ;if error, punt
  223.         
  224.         MOVE.L    A0,D2            ;remember base
  225.         MOVE.L    A0,A1            ;that's the destination
  226.         MOVE.L    A2,A0            ;AddResPatchis source
  227.         MOVE.L    D1,D0            ;set up size
  228.         _BlockMove            ;move it in
  229.  
  230. ; patch in the new routine
  231.  
  232.         MOVE.L    D2,A0            ;get new address
  233.         MOVE.W    #$14D,D0        ;trap ID of AddResMenu
  234.         _SetTrapAddress            ;patch it in
  235.         
  236. ; all done so exit to shell
  237.  
  238.         _ExitToShell
  239.  
  240. ; handle the error case by beeping
  241.  
  242. NoInstall
  243.         MOVE    #6,-(SP)
  244.         _SysBeep
  245.         
  246.         _ExitToShell        
  247.